/*
 * @Author: 13177709051 3506463075@qq.com
 * @Date: 2024-11-21 23:24:46
 * @LastEditors: 13177709051 3506463075@qq.com
 * @LastEditTime: 2024-11-22 22:04:30
 * @FilePath: /linux34/Route.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include "InetAddr.hpp"
#include "ThreadPool.hpp"
#include "LockGuard.hpp"

// class user
// {};
using task_t = std::function<void()>;

class Route
{
public:
    Route()
    {
        pthread_mutex_init(&_mutex, nullptr);
    }
    void CheckOnlineUser(InetAddr &who)
    {
        LockGuard lockguard(&_mutex);
        for (auto &user : _online_user)
        {
            if (user == who)
            {
                LOG(DEBUG, "%s is exists\n", who.AddrStr().c_str());
                return;
            }
        }
        LOG(DEBUG, "%s is not exists, add it\n", who.AddrStr().c_str());
        _online_user.push_back(who);
    }
    // for test

    void Offline(InetAddr &who)
    {
        LockGuard lockguard(&_mutex);
        auto iter = _online_user.begin();
        for (; iter != _online_user.end(); iter++)
        {
            if (*iter == who)
            {
                LOG(DEBUG, "%s is offline\n", who.AddrStr().c_str());
                _online_user.erase(iter);
                break;
            }
        }
    }

    void ForwardHelper(int sockfd, const std::string message, InetAddr who)
    {
        LockGuard lockguard(&_mutex);
        std::string send_message = "[" + who.AddrStr() + "]# " + message;
        for (auto &user : _online_user)
        {
            struct sockaddr_in peer = user.Addr();
            LOG(DEBUG, "Forward message to %s, message is %s\n", user.AddrStr().c_str(), send_message.c_str());
            ::sendto(sockfd, send_message.c_str(), send_message.size(), 0, (struct sockaddr *)&peer, sizeof(peer));
        }
    }

    void Forward(int sockfd, const std::string &message, InetAddr &who)
    {
        // 1. 该用户是否在 在线用户列表中呢？如果在，什么都不做，如果不在，自动添加到_online_user
        CheckOnlineUser(who);

        // 1.1 message == "QUIT" "Q"
        if (message == "QUIT" || message == "Q")
        {
            Offline(who);
        }

        // 2. who 一定在_online_user列表里面
        // ForwardHelper(sockfd, message);
        task_t t = std::bind(&Route::ForwardHelper, this, sockfd, message, who);
        ThreadPool<task_t>::GetInstance()->Equeue(t);
    }
    ~Route()
    {
        pthread_mutex_destroy(&_mutex);
    }

private:
    std::vector<InetAddr> _online_user;
    pthread_mutex_t _mutex;
};


// 这段代码定义了一个 Route 类，用于管理在线用户并处理消息转发。它使用了线程池、互斥锁、以及其他辅助类（如 InetAddr、ThreadPool 和 LockGuard）。
// 类成员与依赖
// _online_user：存储在线用户的列表，类型为 std::vector<InetAddr>，每个 InetAddr 代表一个用户的 IP 地址和端口。
// _mutex：互斥锁，确保在线用户列表 _online_user 在多线程环境下安全访问。线程在访问 Route 中的共享资源时会加锁，防止数据竞争。
// 构造函数与析构函数
// 构造函数：初始化互斥锁 _mutex，以确保在多线程环境下可以安全地访问 _online_user。
// 析构函数：销毁互斥锁，释放资源。
// CheckOnlineUser 方法
// 作用：检查用户 who 是否已经在 _online_user 中，如果已经存在，不做任何处理；如果不存在，则将其添加到 _online_user 中。
// 加锁：使用 LockGuard 来保证 _online_user 的访问是线程安全的，即确保不会在多线程环境下发生竞争条件。
// 遍历：通过迭代器遍历 _online_user，比较每个 user 是否等于 who（InetAddr 的 operator== 比较函数）。
// 日志：使用 LOG(DEBUG, ...) 打印调试信息。
// Offline 方法
// 作用：将用户 who 从 _online_user 中移除，表示该用户下线。
// 加锁：使用 LockGuard 加锁，确保多线程环境下 _online_user 的安全修改。
// 遍历：遍历 _online_user，如果找到了与 who 匹配的用户，则移除该用户并输出调试日志。
// ForwardHelper 方法
// 作用：将 message 转发给所有在线用户。
// 加锁：再次使用 LockGuard 来保证多线程安全，避免并发访问 _online_user。
// 构造发送消息：构造一个格式化的消息，包含发送者的地址和消息内容。
// 发送消息：遍历 _online_user，对每个在线用户通过 sendto 发送消息。sendto 是一个 socket 函数，用于发送数据报（UDP）。
// Forward 方法
// 作用：处理消息转发的逻辑。
// 检查用户是否在线：调用 CheckOnlineUser 确保 who 在 _online_user 中。如果不在，则会被自动添加。
// 退出消息处理：如果 message 是 "QUIT" 或 "Q"，则调用 Offline 方法让该用户下线。
// 任务转发：将转发消息的任务包装成一个 task_t（即 std::function<void()> 类型的任务），并提交给线程池。
// 线程池：使用 ThreadPool<task_t>::GetInstance()->Equeue(t) 将消息转发任务异步地提交到线程池进行处理。这意味着消息的发送不会阻塞主线程，而是由线程池中的工作线程去执行。